package org.voidness.oje2d.gui;

import org.lwjgl.opengl.GL11;
import org.voidness.oje2d.Engine;
import org.voidness.oje2d.GLColor;
import org.voidness.oje2d.GLImage;
import org.voidness.oje2d.Vector2D;

/** A window widget to use with the GUI engine. */
public class Window extends Widget {
    /** The window's top left corner image index */
    public static final int TOPLEFT = 0;

    /** The window's top right corner image index */
    public static final int TOPRIGHT = 1;

    /** The window's bottom left corner image index */
    public static final int BOTTOMLEFT = 2;

    /** The window's bottom right corner image index */
    public static final int BOTTOMRIGHT = 3;

    /** The window's top face image index */
    public static final int TOPCENTER = 4;

    /** The window's left face image index */
    public static final int LEFT = 5;

    /** The window's right face image index */
    public static final int RIGHT = 6;

    /** The window's bottom face image index */
    public static final int BOTTOMCENTER = 7;

    /** The window's background image */
    public static final int BACK = 8;

    /** The images for the corners */
    private GLImage[] images = null;

    /** The image in the case where we want only one image */
    private GLImage image = null;

    /** Whether the window is beeing grabbed */
    private boolean grabbed;

    /** The position where the window was grabbed */
    private Vector2D grabPosition = null;

    /** Whether this window is fixed or not */
    private boolean fixed;

    /** Whether this is a simple window, i.e., one image only */
    private boolean simpleWindow;

    /** The color of the window */
    private GLColor color = null;

    /**
     * Constructor for the window class.
     * 
     * @param mWidth The window's width
     * @param mHeight The window's height
     */
    public Window(int mWidth, int mHeight) {
        // Call the widget's constructor
        super(mWidth, mHeight);

        // Let's center our window on screen

        // The center of the display window
        xPos = Engine.getInstance().getDisplayBounds().getX() / 2;
        yPos = Engine.getInstance().getDisplayBounds().getY() / 2;

        // Align the window so it's center is in the center of the display
        xPos -= width / 2;
        yPos -= height / 2;

        init();
    }

    /**
     * A more complex constructor for the window.
     * 
     * @param mX The window's position in the X axis
     * @param mY The window's position in the Y axis
     * @param mWidth The window's width
     * @param mHeight The window's height
     */
    public Window(int mX, int mY, int mWidth, int mHeight) {
        super(mX, mY, mWidth, mHeight);

        init();
    }

    /**
     * Initializes the window's parameters
     */
    private void init() {
        // Set window as not beeing grabbed and not fixed
        grabbed = false;
        grabPosition = new Vector2D(-1, -1);
        fixed = false;
        color = GLColor.WHITE;
    }

    /**
     * (Re)defines whether this window is fixed on screen or not
     * 
     * @param mFixed True for a fixed window
     */
    public void setFixed(boolean mFixed) {
        fixed = mFixed;
    }

    /**
     * Returns whether this window is fixed
     * 
     * @return True if it is, false otherwise
     */
    public boolean isFixed() {
        return fixed;
    }

    /**
     * (Re)defines this window's alpha value
     * 
     * @param mAlpha The alpha value to set
     */
    public void setAlpha(float mAlpha) {
        if (color == null)
            color = new GLColor(1.0f, 1.0f, 1.0f, mAlpha);
        else
            color =
                    new GLColor(color.getRed(), color.getGreen(), color
                            .getBlue(), mAlpha);
    }

    /**
     * (Re)defines this window's color
     * 
     * @param mColor The color to set
     */
    public void setColor(GLColor mColor) {
        color = mColor;
    }

    /**
     * Defines the images for the window.
     * 
     * @param mCorners A GLImage array with the corners previously loaded
     * @param mFaces A String array with the path for the faces' images
     * @param mBack A String with the path for the background image
     */
    public void setImages(GLImage[] mCorners, String[] mFaces, String mBack) {
        images = new GLImage[9];

        // Define the corners
        images[TOPLEFT] = mCorners[0];
        images[TOPRIGHT] = mCorners[1];
        images[BOTTOMLEFT] = mCorners[2];
        images[BOTTOMRIGHT] = mCorners[3];

        // Now calculate the size of the faces, based on the
        // corners's sizes and the window's width and height
        int centerWidth =
                width
                        - (images[TOPLEFT].getWidth() + images[TOPRIGHT]
                                .getWidth());
        int lateralHeight =
                height
                        - (images[TOPLEFT].getHeight() + images[BOTTOMLEFT]
                                .getHeight());
        images[TOPCENTER] =
                new GLImage(mFaces[0], centerWidth,
                        images[TOPLEFT].getHeight(), false);
        images[LEFT] =
                new GLImage(mFaces[1], images[TOPLEFT].getWidth(),
                        lateralHeight, false);
        images[RIGHT] =
                new GLImage(mFaces[2], images[TOPRIGHT].getWidth(),
                        lateralHeight, false);
        images[BOTTOMCENTER] =
                new GLImage(mFaces[3], centerWidth, images[BOTTOMLEFT]
                        .getHeight(), false);

        // Now calculate the background size based on the rest
        images[BACK] =
                new GLImage(mBack, width
                        - (images[TOPLEFT].getWidth() + images[TOPRIGHT]
                                .getWidth()), height
                        - (images[TOPLEFT].getHeight() + images[BOTTOMLEFT]
                                .getHeight()), true);

        simpleWindow = false;
    }

    /**
     * (Re)defines this window's only image. To use only with simple windows
     * 
     * @param mImage The image to set
     */
    public void setImage(GLImage mImage) {
        image = mImage;

        simpleWindow = true;
    }

    /**
     * Is the window beeing grabbed by the mouse?
     * 
     * @return True if yes, false if no
     */
    public boolean isGrabbed() {
        return grabbed;
    }

    /**
     * Updates the window's position based on the mouse movement delta. The
     * "if (grabbed)" instruction is just a safeguard, as the gui engine already
     * performs the check in it's update method.
     */
    public void updatePosition() {
        if (grabbed && Engine.getInstance().getMouseLeftButtonDown()) {
            if (!fixed) {
                xPos += Engine.getInstance().getMouseDelta().getX();
                yPos -= Engine.getInstance().getMouseDelta().getY();
            }
        }
    }

    /**
     * Sets this window as grabbed or not by the mouse.
     * 
     * @param mGrabbed True for grabbed, false for not grabbed
     */
    public void setGrabbed(boolean mGrabbed) {
        grabbed = mGrabbed;
        grabPosition.setX(Engine.getInstance().getMouseX());
        grabPosition.setY(Engine.getInstance().getMouseY());
    }

    public void drawToolTips() {
        // Cycle the widget list and draw all
        for (int i = 0; i < widgetList.size(); i++) {
            Widget widget = (Widget) widgetList.elementAt(i);
            widget.drawToolTip();
        }
    }

    public void draw(GLColor mColor) {
        color = mColor;

        if (simpleWindow)
            drawSimple();
        else
            drawComplex();
    }

    private void drawSimple() {
        // Only draw if all images are set
        if (image == null)
            return;

        image.setColor(color != null ? color : GLColor.WHITE);

        // Draw only if visible
        if (!visible)
            return;

        // Now draw (from top to bottom, left to right)
        image.draw(xPos, yPos, color.getAlpha());

        // Cycle the widget list and draw all
        for (int i = 0; i < widgetList.size(); i++) {
            Widget widget = (Widget) widgetList.elementAt(i);
            widget.draw(color);
        }
    }

    public void drawShadows() {
        GLColor mColor = new GLColor(0.0f, 0.0f, 0.0f, 0.1f);
        mColor.set();

        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL11.GL_BLEND);

        // Drawing position
        int drawX = xPos - 5;
        int drawY = yPos + 5;

        GL11.glBegin(GL11.GL_QUADS);
        GL11.glNormal3f(0.0f, 0.0f, 1.0f);
        GL11.glTexCoord2f(0.0f, 1.0f);
        GL11.glVertex2i(drawX, Engine.getInstance().getDisplayBounds().getY()
                - drawY);
        GL11.glTexCoord2f(0.0f, 0.0f);
        GL11.glVertex2i(drawX, Engine.getInstance().getDisplayBounds().getY()
                - drawY - getHeight());
        GL11.glTexCoord2f(1.0f, 0.0f);
        GL11.glVertex2i(drawX + getWidth() + 10, Engine.getInstance()
                .getDisplayBounds().getY()
                - drawY - getHeight());
        GL11.glTexCoord2f(1.0f, 1.0f);
        GL11.glVertex2i(drawX + getWidth() + 10, Engine.getInstance()
                .getDisplayBounds().getY()
                - drawY);
        GL11.glEnd(); // Done Building Our Quad (Character)
        GL11.glDisable(GL11.GL_BLEND);

        GL11.glDisable(GL11.GL_TEXTURE_2D);
        mColor.reset();
    }

    /**
     * Draws the window and all sub-widgets.
     */
    public void drawComplex() {
        // Only draw if all images are set
        if (images[TOPLEFT] == null || images[TOPCENTER] == null
                || images[TOPRIGHT] == null || images[LEFT] == null
                || images[BACK] == null || images[RIGHT] == null
                || images[BOTTOMLEFT] == null || images[BOTTOMCENTER] == null
                || images[BOTTOMRIGHT] == null)
            return;

        for (int i = 0; i < images.length; i++)
            images[i].setColor(color != null ? color : GLColor.WHITE);

        // Draw only if visible
        if (!visible)
            return;

        // drawShadows(); // Next release ;)

        // Drawing position
        int drawX = xPos;
        int drawY = yPos;

        // Now draw (from top to bottom, left to right)
        images[TOPLEFT].draw(drawX, drawY, color.getAlpha());
        drawX += images[TOPLEFT].getWidth();
        images[TOPCENTER].draw(drawX, drawY, color.getAlpha());
        drawX += images[TOPCENTER].getWidth();
        images[TOPRIGHT].draw(drawX, drawY, color.getAlpha());
        drawX = xPos;
        drawY += images[TOPLEFT].getHeight();
        images[LEFT].draw(drawX, drawY, color.getAlpha());
        drawX += images[LEFT].getWidth();
        images[BACK].draw(drawX, drawY, color.getAlpha());
        drawX += images[BACK].getWidth();
        images[RIGHT].draw(drawX, drawY, color.getAlpha());
        drawX = xPos;
        drawY += images[RIGHT].getHeight();
        images[BOTTOMLEFT].draw(drawX, drawY, color.getAlpha());
        drawX += images[BOTTOMLEFT].getWidth();
        images[BOTTOMCENTER].draw(drawX, drawY, color.getAlpha());
        drawX += images[BOTTOMCENTER].getWidth();
        images[BOTTOMRIGHT].draw(drawX, drawY, color.getAlpha());

        // Cycle the widget list and draw all
        for (int i = 0; i < widgetList.size(); i++) {
            Widget widget = (Widget) widgetList.elementAt(i);
            widget.draw(color);
        }
    }
}